package cn.wetcland.urban.common.config.exception;

import cn.dev33.satoken.exception.*;
import cn.wetcland.urban.common.AjaxResponse;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.stream.Collectors;

@RestControllerAdvice
public class WebExceptionHandler {

    /**
     * 将自定义异常捕获，以友好的方式告知用户
     * @param customerException 自定义异常
     * @return AjaxResponse
     */
    @ResponseBody
    @ExceptionHandler(CustomerException.class)
    public AjaxResponse customerException(CustomerException customerException) {
        if (CustomerExceptionTypeEnum.SYSTEM_ERROR.getCode() == customerException.getCode()) {
            System.err.println(customerException.getMessage());
        }
        return AjaxResponse.error(customerException);
    }

    @ResponseBody
    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public AjaxResponse BindException(Exception e) {
        e.printStackTrace();
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = ((MethodArgumentNotValidException) e);
            BindingResult bindingResult = ex.getBindingResult();
            StringBuilder res = new StringBuilder();
            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                res.append(fieldError.getDefaultMessage()).append("，");
            }
            return AjaxResponse.error(new CustomerException(CustomerExceptionTypeEnum.ASSERT_WARNING, res.toString()));
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException ex = ((ConstraintViolationException) e);
            for (ConstraintViolation<?> constraintViolation : ex.getConstraintViolations()) {
                System.out.println(constraintViolation.getMessage());
            }
        } else if (e instanceof BindException) {
            BindException  ex = ((BindException) e);
            StringBuilder res = new StringBuilder();
            for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
                res.append(fieldError.getDefaultMessage()).append("，");
            }
            return AjaxResponse.error(new CustomerException(CustomerExceptionTypeEnum.ASSERT_WARNING, res.toString()));
        }
        return AjaxResponse.error(new CustomerException(CustomerExceptionTypeEnum.ASSERT_WARNING, e.getLocalizedMessage()));
    }

    @ResponseBody
    @ExceptionHandler(BadSqlGrammarException.class)
    public AjaxResponse SQLSyntaxErrorException(BadSqlGrammarException badSqlGrammarException) {
        System.err.println(badSqlGrammarException.getSql());
        System.err.println(badSqlGrammarException.getSQLException().getMessage());
        badSqlGrammarException.printStackTrace();
        return AjaxResponse.error(CustomerExceptionTypeEnum.ILLEGAL_OPERATION_ERROR, "请检查输入的查询条件字段是否符合规范");
    }

    @ResponseBody
    @ExceptionHandler(IllegalArgumentException.class)
    public AjaxResponse IllegalArgumentException(IllegalArgumentException illegalArgumentException) {
        System.err.println(illegalArgumentException.getMessage());
        return AjaxResponse.error(CustomerExceptionTypeEnum.ILLEGAL_OPERATION_ERROR, "请检查请求量是否符合规范");
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public AjaxResponse MethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException methodArgumentTypeMismatchException) {
        System.err.println(methodArgumentTypeMismatchException.getMessage());
        return AjaxResponse.error(CustomerExceptionTypeEnum.ILLEGAL_OPERATION_ERROR, "请检查请求参数类型是否匹配");
    }

    @ResponseBody
    @ExceptionHandler(SaTokenException.class)
    public AjaxResponse NotLoginException(SaTokenException saTokenException) {
        System.err.println(saTokenException.getMessage());
        if (saTokenException instanceof NotBasicAuthException) {
            System.out.println("NotBasicAuthException 异常");
        } else if (saTokenException instanceof NotLoginException) {
            return AjaxResponse.error(CustomerExceptionTypeEnum.USER_AUTHORIZE_EXPIRE, "登录失效，请重新登录");
        } else if (saTokenException instanceof NotPermissionException) {
            return AjaxResponse.error(CustomerExceptionTypeEnum.USER_PERMISSION_LACK, "无访问权限");
        } else if (saTokenException instanceof NotRoleException) {
            return AjaxResponse.error(CustomerExceptionTypeEnum.USER_PERMISSION_LACK, "缺失角色权限");
        }
        return AjaxResponse.error(CustomerExceptionTypeEnum.OTHER_ERROR, saTokenException.getMessage());
    }
    /**
     * 处理程序员在程序中未能捕获（遗漏的）异常
     * @param e Exception
     * @return AjaxResponse
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public AjaxResponse exception(Exception e) {
        e.printStackTrace();
        return AjaxResponse.error(new CustomerException(CustomerExceptionTypeEnum.OTHER_ERROR, "未知异常"));
    }

}
